#import "SocketObserver.h"

@interface SocketObserver(PrivateMethods)
- (void) callback;
@end

static void socketCallback(CFSocketRef socket, CFSocketCallBackType type,
	CFDataRef address, const void* socketData, void* context)
{
	[((SocketObserver*) context) callback];
}

@implementation SocketObserver

- (id) initWithRunLoop: (CFRunLoopRef) runLoop
	socket: (int) theSocket
	delegate: (id) delegate
	context: (void*) delContext
{
	if(self = [super init])
	{
		_runLoop = (CFRunLoopRef) CFRetain(runLoop);
		
		CFSocketContext theContext = { 0 };
		theContext.info = self;
		_socket = CFSocketCreateWithNative(NULL, theSocket,
			kCFSocketReadCallBack, socketCallback, &theContext);
		NSAssert(_socket, @"_socket should never be NULL");
		
		CFSocketSetSocketFlags(_socket, CFSocketGetSocketFlags(_socket) & ~kCFSocketCloseOnInvalidate);
		
		_source = CFSocketCreateRunLoopSource(NULL, _socket, 0);
		NSAssert(_source, @"_source should never be NULL");
		
		CFRunLoopAddSource(_runLoop, _source, kCFRunLoopDefaultMode);
		
		[self setDelegate: delegate];
		[self setContext: delContext];
	}
	return self;
}

- (void) dealloc
{
	[self setDelegate: nil];
	CFRunLoopRemoveSource(_runLoop, _source, kCFRunLoopDefaultMode);
	CFRelease(_source);
	CFSocketInvalidate(_socket);
	CFRelease(_socket);
	CFRelease(_runLoop);
	[super dealloc];
}

- (CFRunLoopRef) runLoop
{
	return _runLoop;
}

- (int) socket
{
	return CFSocketGetNative(_socket);
}

- (id) delegate
{
	return _delegate;
}

- (void) setDelegate: (id) delegate
{
	[_delegate autorelease];
	_delegate = [delegate retain];
}

- (void*) context
{
	return _context;
}

- (void) setContext: (void*) context
{
	_context = context;
}

@end

@implementation SocketObserver(PrivateMethods)

- (void) callback
{
	if([_delegate respondsToSelector: @selector(observeSocket:context:)])
		[_delegate observeSocket: CFSocketGetNative(_socket) context: _context];
}

@end
